package com.hivis.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator.Builder;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

/***
 * 
 * 1，根据上面生成一个由base64编码的token，该token由Header，Payload，Signature组成。

 * 2，token作为用户请求的标识，客户端保存这token的全部信息。服务端只需要保存token的Signature部分。

 * 3，服务端把token的Signature存于redis和服务器的数据库中。

 * 4，客户端请求的数据附带token，服务端拿到token，首先校验token，以防token伪造。校验规则如下：
 *	4.1，拆分出token的Header，Payload，Signature。
	4.2，校验Signature，通过token的header和payload生成Signature，看看生成的Signature是否和客户端附带上来的Signature一致。如果一致继续请求操作，不一致则打回操作
	4.3，查看Signature是否存在服务器的redis和数据库中。如果不存在则打回请求操作
 *
 *
 */
public class TokenUtil {
	public static final  String TOKEN_AES_KEY = "dian@xin@2018#!0806";
    public static final  String REFREH_TOKEN_AES_KEY = "xiangli8RefreshToken";
    public static final  String JWT_TYP = "JWT";
    public static final  String JWT_ALG = "AES";
    public static final  String JWT_EXP = "30";
    public static final  String JWT_ISS = "xiangli8";

    private static RSAPublicKey publicKey; // 公钥
    private static RSAPrivateKey privateKey; // 私钥
    
    static{
    	KeyPairGenerator keyPairGen;
		try {
			keyPairGen = KeyPairGenerator.getInstance("RSA");
			keyPairGen.initialize(1024); // 密钥位数
			// 动态生成密钥对，这是当前最耗时的操作，一般要2s以上。
			KeyPair keyPair = keyPairGen.generateKeyPair();
			// 公钥
			publicKey = (RSAPublicKey) keyPair.getPublic();
			// 私钥
			privateKey = (RSAPrivateKey) keyPair.getPrivate();
			
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
    
    public static String createToken(Map<String, String> claims){
//    	Map<String, Object> map = new HashMap<>();
		try {
//			String key = new String(Base64Util.decryptBASE64(base64Secret), "utf-8");
//			if(StringUtil.strIsNullOrEmpty(base64Secret) ||
//					!TOKEN_AES_KEY.equals(key)){
//    	    	map.put("errcode", 40001);
//    	    	map.put("errmsg", "获取access_token时Secret错误");
//    	    }else{
//    			Calendar ca=Calendar.getInstance();
//    			ca.add(Calendar.HOUR_OF_DAY, 2); // token2小时过期
////    			ca.add(Calendar.SECOND, 3);
//    			
//    			Algorithm algorithmRS = Algorithm.RSA256(publicKey, privateKey);
//    			
//    			String token = JWT.create()
//    			        .withIssuer("auth0")
//    			        .withExpiresAt(ca.getTime())
//    			        .withClaim("secret", base64Secret)
//    			        .sign(algorithmRS);
//    			System.out.println("token:" + token);
//    			
//    	    	map.put("errcode", 0);
//    	    	map.put("access_token", token);
//    	    	map.put("expires_in", 7200);
//    	    }
			
			Calendar ca=Calendar.getInstance();
			ca.add(Calendar.HOUR_OF_DAY, 2); // token2小时过期

			Algorithm algorithmRS = Algorithm.RSA256(publicKey, privateKey);
            // 设置头部信息
            Map<String, Object> header = new HashMap<String, Object>();
            header.put("typ", "JWT");
            header.put("alg", "RS256");

            Builder builder = JWT.create()
//                                .withHeader(header)
//								.withIssuer("auth0")
								.withExpiresAt(ca.getTime()); // 过期时间
			for(Map.Entry<String, String> entry : claims.entrySet()){
				builder = builder.withClaim(entry.getKey(), entry.getValue());
			}
			String token = builder.sign(algorithmRS); // 签名
			
			return token;
			
		} catch (JWTCreationException e){
			e.printStackTrace();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	
		return null;
    }
    
    public static boolean verify(String token){
    	try {
    	    Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey);
    	    JWTVerifier verifier = JWT.require(algorithm)
//    	        .withIssuer("auth0")
    	        //.acceptExpiresAt(7200)    // secs for exp
    	        .build(); //Reusable verifier instance
    	    DecodedJWT jwt = verifier.verify(token);
    	    
    	    Map<String, Claim> claims = jwt.getClaims();
//    	    String key=new String(Base64Util.decryptBASE64(jwt.getClaim("secret").asString()), "utf-8");
//    	    if(TOKEN_AES_KEY.equals(key)){
//    	    	return true;
//    	    }
    	    return true;
    	}catch (TokenExpiredException e) { // token过期
            e.printStackTrace();
            return false;
        }catch (JWTVerificationException e){ // 校验失败
    	    //Invalid signature/claims
			e.printStackTrace();
    		return false;
    	}catch (NullPointerException e){
			e.printStackTrace();
    		return false;
    	} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
    }
    
//    /**
//     * 获得token
//     * @param data 自定义数据
//     * @param <T> 自定义数据
//     * @return
//     * @throws Exception
//     */
//    public static <T> String getToken(T data) throws Exception {
//        TokenPlayload<T> userTokenPlayload = new TokenPlayload<>();
//        userTokenPlayload.setExpData(data);
//        String jwt = createJWT(userTokenPlayload);
//        return jwt;
//    }
//
//    /**
//     * 生成jwt的header部分内容
//     * @return
//     * @throws Exception
//     */
//    private static String tokenHeaderBase64() throws Exception {
//        TokenHeader tokenHeader = new TokenHeader();
//        tokenHeader.setTyp(JWT_TYP);
//        tokenHeader.setAlg(JWT_ALG);
//
//        String headerJson = JSON.toJSONString(tokenHeader);
//
//        String headerBase64 = Base64Util.encryptBASE64(headerJson.getBytes());
//
//        return headerBase64;
//    }
//
//    /**
//     * 生成jwt的payload部分内容
//     * @param tokenPlayload
//     * @param <T>自定义的数据块
//     * @return
//     * @throws Exception
//     */
//    private static <T> String tokenPayloadBase64(TokenPlayload<T> tokenPlayload) throws Exception {
//        tokenPlayload.setIss(JWT_ISS);
//        tokenPlayload.setExp(JWT_EXP);
//
//        tokenPlayload.setIat(String.valueOf(System.currentTimeMillis()));
//
//        String headerJson =JSON.toJSONString(tokenPlayload);
//
//        String headerBase64 = Base64Util.encryptBASE64(headerJson.getBytes());
//
//        return headerBase64;
//    }
//
//    /**
//     * 生成JWT
//     * @return
//     */
//    public static <T> String createJWT(TokenPlayload<T> tokenPlayload) throws Exception {
//        StringBuilder jwtSb = new StringBuilder();
//        StringBuilder headerPlayloadSb = new StringBuilder();
//
//        String tokenHeaderBase64 = tokenHeaderBase64();
//        String tokenPayloadBase64 = tokenPayloadBase64(tokenPlayload);
//
//        jwtSb.append(tokenHeaderBase64);
//        jwtSb.append(".");
//        jwtSb.append(tokenPayloadBase64);
//        jwtSb.append(".");
//
//        headerPlayloadSb.append(tokenHeaderBase64);
//        headerPlayloadSb.append(tokenPayloadBase64);
//
//        String headerPlayloadSalt = SaltUtil.addSalt(headerPlayloadSb.toString());
//
//        String key = AesUtil.initKey(TOKEN_AES_KEY+tokenPlayload.getIat());
//
//        String  signature = Base64Util.encryptBASE64(AesUtil.encrypt(headerPlayloadSalt.getBytes(),key));
//
//        jwtSb.append(signature);
//
//        return Base64Util.encryptBASE64(jwtSb.toString().getBytes());
//    }
//
//    /**
//     * 校验token是否是服务器生成的，以防token被修改
//     * @param jwtBase64
//     * @return
//     * @throws Exception
//     */
//    public static <T> boolean verifyJWT(String jwtBase64) throws Exception {
//        String jwt = new String (Base64Util.decryptBASE64(jwtBase64));
//
//        if(!jwt.contains(".")){
//            return false;
//        }
//
//        String[] jwts = jwt.split("\\.");
//        if(jwts.length<3){
//            return false;
//        }
//
//        TokenPlayload tTokenPlayload =  JSON.parseObject(new String(Base64Util.decryptBASE64(jwts[1])),TokenPlayload.class);
//        String key = AesUtil.initKey(TOKEN_AES_KEY+tTokenPlayload.getIat());
//
//        //解析出header跟playload
//        StringBuilder headerPlayloadSb = new StringBuilder();
//        headerPlayloadSb.append(jwts[0]);
//        headerPlayloadSb.append(jwts[1]);
//
//        //解析signature
//        String  headerPlayloadSalt = new String (AesUtil.decrypt(Base64Util.decryptBASE64(jwts[2]),key));
//
//        return SaltUtil.verifyPwd(headerPlayloadSb.toString(),headerPlayloadSalt);
//    }
//
//
//
    public static void main(String[] args) throws Exception {
//        String jwt = getToken(new User(1L,"你是逗逼"));
//        System.out.println("jwt:"+jwt);
//        System.out.println(Base64Util.encryptBASE64(TokenUtil.TOKEN_AES_KEY.getBytes()));
//    	String base64Secret = Base64Util.encryptBASE64(TokenUtil.TOKEN_AES_KEY.getBytes());
//    	String token = TokenUtil.createToken("ZGlhbkB4aW5AMjAxOCMhMDgwNg==");
//    	System.out.println("verify token:" + TokenUtil.verify(token));
    }
}
